﻿
package extremefx.ui {
	import extremefx.IDisposable;
	import extremefx.events.EventHandler;
	import extremefx.events.MouseEventArgs;
	
	import flash.display.DisplayObjectContainer;
	import flash.events.EventPhase;
	import flash.events.MouseEvent;	

	/**
	 * @author Marcelo Volmaro
	 */
	public final class ButtonSprite implements IDisposable {
		private static const _bList:Vector.<ButtonSprite> = new Vector.<ButtonSprite>();
		
		private var _do:DisplayObjectContainer;
		private var _enabled:Boolean;
		private var _focus:Boolean;

		public function ButtonSprite(pDisplayObject:DisplayObjectContainer) {
			_do = pDisplayObject;
			pDisplayObject.mouseChildren = false;
			
			_bList.push(this);
		}
		
		public function get enabled():Boolean {
			return _enabled;
		}
		
		public function set enabled(pE:Boolean):void {
			if (pE && !_enabled){
				_do.addEventListener(MouseEvent.MOUSE_OVER, _mouseOver, false, 0, true);
				_do.addEventListener(MouseEvent.MOUSE_OUT, _mouseOut, false, 0, true);
				_do.addEventListener(MouseEvent.MOUSE_DOWN, _press, false, 0, true);
				_do.addEventListener(MouseEvent.MOUSE_UP, _release, false, 0, true);
				
			} else if (!pE && _enabled){
				_do.removeEventListener(MouseEvent.MOUSE_OVER, _mouseOver);
				_do.removeEventListener(MouseEvent.MOUSE_OUT, _mouseOut);
				_do.removeEventListener(MouseEvent.MOUSE_DOWN, _press);
				_do.removeEventListener(MouseEvent.MOUSE_UP, _release);
			}
			
			_enabled = pE;
		}
		
		public function get mouseEnabled():Boolean {
			return _do.mouseEnabled;
		}
		
		public function set mouseEnabled(pE:Boolean):void {
			_do.mouseEnabled = pE;
		}
		
		private function _release(event:MouseEvent):void {
			_removeStageListener();
			var e:MouseEventArgs = new MouseEventArgs(event); 
			
			if (_focus){
				_focus = false;
				if (_eOnRelease) _eOnRelease.fire(e);
				
			} else {
				if (_eOnRollOver) _eOnRollOver.fire(e);
			}
		}

		private function _press(event:MouseEvent):void {
			if (!_focus) _do.stage.addEventListener(MouseEvent.MOUSE_UP, _mouseUpHandler,false,0,true);
			
			for each(var mh:ButtonSprite in _bList){
				mh.mouseEnabled = (mh == this);
			}
			
			_focus = true;
			event.stopPropagation();
			
			if (_eOnPress) _eOnPress.fire(new MouseEventArgs(event));
		}
		
		private var _disposing:Boolean;

		private function _mouseUpHandler(event:MouseEvent):void {
			if (event.eventPhase < EventPhase.AT_TARGET) return;
			
			_removeStageListener();
			_focus = false;
			event.stopPropagation();
			
			if (_eOnReleaseOutside) _eOnReleaseOutside.fire(new MouseEventArgs(event));
		}
		
		private function _removeStageListener():void {
			for each(var mh:ButtonSprite in _bList){
				mh.mouseEnabled = true;
			}
			
			if (_do && _do.stage) _do.stage.removeEventListener(MouseEvent.MOUSE_UP, _mouseUpHandler);
		}

		private function _mouseOut(event:MouseEvent):void {
			event.stopPropagation();
			
			var e:MouseEventArgs = new MouseEventArgs(event); 
			if (event.buttonDown){
				if (_eOnDragOut) _eOnDragOut.fire(e);
				
			} else {
				if (_eOnRollOut) _eOnRollOut.fire(e);	
			}
		}

		private function _mouseOver(event:MouseEvent):void {
			event.stopPropagation();
			
			var e:MouseEventArgs = new MouseEventArgs(event);
			if (event.buttonDown){
				if (_eOnDragOver) _eOnDragOver.fire(e);
				
			} else {
				if (_eOnRollOver) _eOnRollOver.fire(e);	
			}
		}

		public function dispose():void {
			if (_disposing) return;
			_disposing = true;

			if (_eOnPress) _eOnPress.dispose();
			if (_eOnRelease) _eOnRelease.dispose();
			if (_eOnReleaseOutside) _eOnReleaseOutside.dispose();
			if (_eOnRollOver) _eOnRollOver.dispose();
			if (_eOnRollOut) _eOnRollOut.dispose();
			if (_eOnDragOver) _eOnDragOver.dispose();
			if (_eOnDragOut) _eOnDragOut.dispose();

			enabled = false;
			
			var idx:int = _bList.indexOf(this);
			if (idx != -1) _bList.splice(idx, 1);
		}
		
		private var _eOnPress:EventHandler;
		public function get onPress():EventHandler{
			if (_eOnPress == null) _eOnPress = new EventHandler(this);
			return _eOnPress;
		}
		
		private var _eOnRelease:EventHandler;
		public function get onRelease():EventHandler{
			if (_eOnRelease == null) _eOnRelease = new EventHandler(this);
			return _eOnRelease;
		}
		
		private var _eOnReleaseOutside:EventHandler;
		public function get onReleaseOutside():EventHandler{
			if (_eOnReleaseOutside == null) _eOnReleaseOutside = new EventHandler(this);
			return _eOnReleaseOutside;
		}
		
		private var _eOnRollOver:EventHandler;
		public function get onRollOver():EventHandler{
			if (_eOnRollOver == null) _eOnRollOver = new EventHandler(this);
			return _eOnRollOver;
		}
		
		private var _eOnRollOut:EventHandler;
		public function get onRollOut():EventHandler{
			if (_eOnRollOut == null) _eOnRollOut = new EventHandler(this);
			return _eOnRollOut;
		}
		
		private var _eOnDragOver:EventHandler;
		public function get onDragOver():EventHandler{
			if (_eOnDragOver == null) _eOnDragOver = new EventHandler(this);
			return _eOnDragOver;
		}
		
		private var _eOnDragOut:EventHandler;
		public function get onDragOut():EventHandler{
			if (_eOnDragOut == null) _eOnDragOut = new EventHandler(this);
			return _eOnDragOut;
		}
	}
}
